﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AutomationView
{
    public abstract class BaseEngine
    {
        protected BaseEngine()
        {
            States = new Dictionary<ViewState, List<Operation>>();
            Handlers = new Dictionary<ViewState, Func<Operation, ViewState>>();

            Handlers.Add(ViewState.Common.End, op =>
            {
                this.End(); 
                return ViewState.Common.End;
            });

            States.Add(ViewState.Common.End, new List<Operation> { });
        }

        #region Definition

        public Dictionary<ViewState, List<Operation>> States { get; private set; }

        protected Dictionary<ViewState, Func<Operation, ViewState>> Handlers { get; private set; }

        ViewState state;
        public ViewState CurrentState
        {
            get { return state; }
            private set
            {
                if (state == null || state.Name != value.Name)
                {
                    state = value;
                    if (this.StateChanged != null) StateChanged(state);
                    if (States[state].Count < 1)
                        Accept(Operation.Empty);  //Auto transfer to next state   
                }
            }
        }

        BaseEngine subEngine;
        /// <summary>
        /// Enable engine accept sub engine's operation and transfer to sub engine.
        /// </summary>
        protected BaseEngine CurrentSubEngine
        {
            get { return subEngine; }
            set
            {
                if (value != null)
                {
                    value.StateChanged += s =>
                    {
                        if (this.StateChanged != null) StateChanged(s);     //*** Should notify state level afterwards
                    };
                }
                subEngine = value;
            }
        }
        #endregion

        #region Event
        public event Action<ViewState> StateChanged;
        
        #endregion

        public virtual void Start()
        {
            this.CurrentState = ViewState.Common.Start;
        }

        protected abstract void End();

        protected internal void Accept(Operation op)
        {
            if (this.CurrentSubEngine == null || this.CurrentSubEngine.CurrentState == ViewState.Common.End)
            {
                //Empty operation must be applied to state without operations defined.
                if ((op == Operation.Empty && States[CurrentState].Count > 0) ||
                    (op != Operation.Empty && States[CurrentState].Count(o => o.Name == op.Name) < 1))    //May need a OperationType class
                    throw new InvalidOperationException();

                this.CurrentState = Handlers[CurrentState](op);
            }
            else
            {
                this.CurrentSubEngine.Accept(op);
            }
        }

    }
}
